/* 
 * gdith.c --
 *
 *      Procedures dealing with grey-scale and mono dithering, 
 *      as well as X Windows set up procedures.
 *
 */

/*
 * Copyright (c) 1995 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

/*
 * Portions of this software Copyright (c) 1995 Brown University.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement
 * is hereby granted, provided that the above copyright notice and the
 * following two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
 * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
 * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include <math.h>
#include "video.h"
#include "proto.h"
#include "dither.h"

#ifdef USE_ATI
#include "vhar128.h"
#endif

#ifdef __STDC__
#include <stdlib.h>
#include <string.h>
#endif


/* 
   Changes to make the code reentrant:
      X variables now passed in xinfo: display, ximage,cmap,window, gc, etc
      De-globalized: ditherType, matched_depth, totNumFrames
      vid_stream->film_has_ended instead of FilmState

   Additional changes:
      Now can name and position each movie window individually
      DISABLE_DITHER cpp define - do not include dither code if defined
      NOFRAMECOUNT cpp define - do not count frames when running without
         controls
      Short circuit InitColorDisplay if not displaying anything
      ExistingWindow default now 0
   -lsh@cs.brown.edu (Loring Holden)
*/

/* Frame Rate Info */
extern int framerate;

/* Video rates table */
/* Cheat on Vid rates, round to 30, and use 30 if illegal value 
   Except for 9, where Xing means 15, and given their popularity, we'll
   be nice and do it */
static double VidRateNum[16]={ 30, 23.97, 24, 25, 29.97, 30, 50, 59.94, 
                            60, 15, 30, 30, 30, 15, 30, 30 };

#ifdef CALCULATE_FPS
static inline void TimestampFPS( LWMPEG_VidStream* vid_stream )
{
    MPEGvideo* mpeg = (MPEGvideo*) vid_stream->_smpeg;

    vid_stream->frame_time[vid_stream->timestamp_index] = mpeg->Time();
    ++vid_stream->timestamp_index;
    if ( vid_stream->timestamp_index == FPS_WINDOW ) {
        vid_stream->timestamp_index = 0;
    }
}
#endif

/*
   Do frame rate control.  Returns _skipFrame
*/
#define LOOSE_MPEG_SCHEDULING
#ifdef LOOSE_MPEG_SCHEDULING
#define MAX_FRAME_SKIP  4
#define MAX_FUDGE_TIME  (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)
#else
#ifdef TIGHT_MPEG_SCHEDULING
#define MAX_FRAME_SKIP  1
#define MAX_FUDGE_TIME  (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)
#else
#define MAX_FRAME_SKIP  3
#define MAX_FUDGE_TIME  (MAX_FRAME_SKIP*vid_stream->_oneFrameTime)
#endif /* TIGHT_MPEG_SCHEDULING */
#endif /* LOOSE_MPEG_SCHEDULING */
#define FUDGE_TIME	(((MAX_FRAME_SKIP+1)/2)*vid_stream->_oneFrameTime)

/* This results in smoother framerate, but more dropped frames on
   systems that can play most of the video fine, but have problems
   with jerkiness in a few spots.
*/
//#define SLOW_START_SCHEDULING
#define SLOW_START_INCREMENT    0.3

/* Define this to debug the frame scheduler */
//#define DEBUG_MPEG_SCHEDULING

/* Do the hard work of copying from the video stream working buffer to the
   screen display and then calling the update callback.
*/
void LWMPEG_MPEGvideo::DisplayFrame( LWMPEG_VidStream * vid_stream )
{
  Uint16 pitches[3];
  Uint8 *pixels[3];
  static int frameNo = 0;
  char filename[2000];

  pitches[0] = _w;
  pitches[1] = _w / 2;
  pitches[2] = _w / 2;
  pixels[0] = (Uint8 *)vid_stream->current->image;
  pixels[1] = (Uint8 *)vid_stream->current->image + pitches[0] * _h;
  pixels[2] = (Uint8 *)vid_stream->current->image + pitches[0] * _h +
                                                    pitches[1] * _h / 2;

  _imgY = pixels[0];
  _imgU = pixels[1];
  _imgV = pixels[2];
  _imgAvailable = true;

  _frameRateDenom = 1;
  switch(vid_stream->picture_rate)
  {
  case 1:
	  _frameRateNum = 23976;
	  _frameRateDenom = 1000;
	  break;
  case 2:
	  _frameRateNum = 24;
	  break;
  case 3:
	  _frameRateNum = 25;
	  break;
  case 4:
	  _frameRateNum = 2997;
	  _frameRateDenom = 100;
	  break;
  case 5:
	  _frameRateNum = 30;
	  break;
  case 6:
	  _frameRateNum = 50;
	  break;
  case 7:
	  _frameRateNum = 5994;
	  _frameRateDenom = 100;
	  break;
  case 8:
	  _frameRateNum = 60;
	  break;
  default:
	  _imgAvailable = false;
  }
}

/*
 *--------------------------------------------------------------
 *
 * ExecuteDisplay --
 *
 *	Actually displays display plane in previously created window.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Updates video frame timing control
 *
 *--------------------------------------------------------------
 */


void LWMPEG_MPEGvideo::ExecuteDisplay( LWMPEG_VidStream* vid_stream, double current_time )
{
    if( ! vid_stream->_skipFrame )
        DisplayFrame(vid_stream);
	else
		vid_stream->_skipFrame--;
}

/* EOF */
